package Cluedo.GUI2;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

import Cluedo.API.CardImage;
import Cluedo.API.CluedoConfig;
import Cluedo.API.CluedoListener;
import Cluedo.API.DisproofAlert;
import Cluedo.API.LanguagePack;
import Cluedo.API.Message;
import Cluedo.API.SoundEngine;
import Cluedo.API.SuggestionAlert;
import Cluedo.API.TickedComboBox;
import Cluedo.Controller.Controller;
import Cluedo.Controller.GameController;
import Cluedo.Game.Card;
import Cluedo.Game.CardCollection;
import Cluedo.Game.Player;
import Cluedo.Game.Position;
import Cluedo.Game.Room;

/**
 * This toolbar is concerned with taking input from the user for suggest/accuse/detective pad
 * and displaying updates for (current) player info / cards / detective pad.
 *
 */
class Toolbar extends JPanel {
	
	private Color[] cardBorderColours = new Color[] { Color.red, Color.green, Color.blue };
	static String iconPath = "Resources/Icons/";

	
	static Hashtable nameColourMappings = new Hashtable();

	static Hashtable colourMappings = new Hashtable();
	{
	    colourMappings.put("red", Color.red);
	    colourMappings.put("blue", Color.blue);
	    colourMappings.put("green", Color.green);
	    colourMappings.put("white", Color.white);
	    colourMappings.put("yellow", Color.yellow);
	    colourMappings.put("magenta", Color.magenta);
	    colourMappings.put("orange", Color.orange);
	}
	
	
	private Hashtable bufferedCardImages = new Hashtable();
	
	private static final String DEFAULT_GROUP = "toolbar";
	
	private static final int standardLabelHeight = 100;
	private static final int standardLabelWidth = 80;
	
	private static final int debugLevel = 0;
	private static String cardImagePath = "Resources/Cards/";
	
	/**
	 * 
	 *  Start of graphical components
	 * 
	 * 
	 */
	
	private TickedComboBox tickedComboBox; 
	
	private JTabbedPane tabs = null;
	
	private CluedoConfig gameConfig = null;
	private GameController gameController = null;
	private JFrame parentFrame = null;
	
	private JLabel realNameLabel = null;
	private JLabel characterNameLabel = null;
	private JLabel rollsRemainingLabel = null;
	
	
	private JButton rollDiceButton = null;
	private JButton accuseButton = null;
	private JButton suggestButton = null;
	
	// **********************************************************************
	// Detective pad panel
	// **********************************************************************
	private JCheckBox suspectCheck[] = null;
	private JTextField suspectText[] = null;
	
	// **********************************************************************
	// End detective pad panel
	// **********************************************************************
	
	// **********************************************************************
	// Show cards panel
	// **********************************************************************
	private CardImage []cardsHeld = null;
	
	// **********************************************************************
	// End show cards panel
	// **********************************************************************
	
	
	// **********************************************************************
	// Info Panel
	// **********************************************************************

	private JLabel playingName = null;
	private JLabel playingChar = null;
	private JLabel movesRemaining = null;
	private JLabel playerColour = null;
	private CardImage diceImage1 = null;
	private CardImage diceImage2 = null;
	private CardImage cimagePlayer = null;
	private CardImage infoIcons[] = new CardImage[4];
	private JLabel candoLabel[] = new JLabel[4];
	private JButton endGo = null; 
	
	// **********************************************************************
	// End Info Panel
	// **********************************************************************
	
	private CardImage[] cardHolders = new CardImage[8];
	
	private int ROOMCOLOR = 0;
	private int SUSPECTCOLOR = 1;
	private int WEAPONCOLOR = 2;
	
	private JComboBox accuseSuspects = null;
	private JComboBox accuseRooms = null;
	private JComboBox accuseWeapons = null;
	
	private JComboBox suggestSuspects = null;
	private JTextField suggestRoom = null;
	private JComboBox suggestWeapons = null;
	
	private boolean ignoreDpadChanges = false;
	

	
	
	/**
	 * Holds an array of 3 (JLabels) with pictures showing the current suggestion.
	 */
	CardImage[] suggestPicArray = null;
	JLabel suggestRoomLabel = null;
	JLabel suggestMaySuggestLabel = null;
	
	/**
	 * The combo lists for the list of suspects and list of weapons.
	 */
	JComboBox[] suggestCombo = null;
	JLabel suggestPreviewLabel = null;
	
	/**
	 * This references the image on the suggest/accuse panel for updating the image
	 */
	private final static int SUSPECT_INDEX = 0;
	/**
	 * This references the image on the suggest/accuse panel for updating the image
	 */
	private final static int WEAPON_INDEX = 1;
	/**
	 * This references the image on the suggest/accuse panel for updating the image
	 */
	private final static int ROOM_INDEX = 2;
	
	// Associated with suggest panel
	
	
	// Associated with accuse panel
	
	/**
	 * Holds an array of 3 (CardImage) with pictures showing current accusation.
	 */
	CardImage[] accusePicArray = null;
	JLabel accusePreviewLabel = null;
	/**
	 * The combo lists for the list of suspects, weapons and rooms
	 */
	JComboBox[] accuseCombo = null;
	// Associated with accuse panel
	
	
	
	// Associated with disproofs
	
	boolean disproofReceived = false;
	Message incomingDisproof = new Message();
	
	// Associated with disproofs
	
	/**
	 * Generates a label with the specified title and type
	 *
	 */
	private static JLabel makeLabel(String title, String type) {
		JLabel label = new JLabel(title);
		label.setToolTipText(type);
		label.setHorizontalAlignment(SwingConstants.CENTER);
		label.setVerticalAlignment(SwingConstants.CENTER);
		
		label.setSize( new Dimension(standardLabelWidth, standardLabelHeight) );
		label.setPreferredSize( new Dimension(standardLabelWidth, standardLabelHeight) );
		label.setMaximumSize( new Dimension(standardLabelWidth, standardLabelHeight) );
		label.setMinimumSize( new Dimension(standardLabelWidth, standardLabelHeight) );
		label.setBorder( BorderFactory.createEtchedBorder() );
		
		return label;
	}
	/**
	 * Set the pointers to the GameController
	 *
	 */
	void setUplink(CluedoConfig gameConfig, GameController gameController) {
		this.gameController = gameController;
		this.gameConfig = gameConfig;
	}
	
	/****************************************************************************
	 *	LISTENER TO CLUEDO GAME CHANGES FROM GAMECONTROLLER
	 *
	 ****************************************************************************
	 */
	
	
	
	/**
	 * We detect an event in the cluedo game
	 *
	 */  
	CluedoListener cluedoListen = new CluedoListener() {
		public void notifyAlert(Message m) {
		    System.out.println("tooblar: notifyAlert && Thread = "+Thread.currentThread().getName() +Thread.currentThread().getClass() + " = "+ m.type);
			if(debugLevel > 3)
				System.out.println("[Toolbar$:GameController] " + m.type + "=" + m.data);
			
			if(m.type.equals("disproofAlert")) {			
				if(disproofReceived == false) {
					incomingDisproof = m;
					
					DisproofAlert disproofAlert = (DisproofAlert)incomingDisproof.parameters.firstElement();
					SuggestionAlert originalSuggestionAlert = disproofAlert.getOriginalSuggestion();
					
					String cardShown = disproofAlert.getCardShown();
					
					System.out.println("Card shown: "+cardShown );
					if(!cardShown.equals("")) {
						markPlayerCard(cardShown);
						updateDPadPanel();
					}
					
					System.out.println("[Toolbar:notifyAlert] Received disproofAlert: "+cardShown);
					
					disproofReceived = true;
					
					
				}
				else {
					incomingDisproof = m;
					DisproofAlert disproofAlert = (DisproofAlert)incomingDisproof.parameters.firstElement();
					

					/** TODO: ADD THIS LINE BACK!! */
					SuggestionNotification suggestionNotification = new SuggestionNotification(parentFrame, disproofAlert, gameController);
					suggestionNotification.setVisible(true);
					
				}
			}
			
			
			// Alias
			if(m.type.equals("commenceGame"))
				m.type = "nextPlayer";
			
			if(m.type.equals("cardMarked")) {
				
			}
			else if(m.type.equals("moveAlert")) {
				SoundEngine.bufferSound("player.move");
				updateInfoPanel();
				updateSuggestPanel();
				
			}
			else if(m.type.equals("playerEliminated")) {
				updateAccusePanel();
			}
			else if(m.type.equals("newRoll")) {
				updateInfoPanel();
				
				SoundEngine.bufferSound("dice.roll");
			}
			else if(m.type.equals("winGame")) {
				SoundEngine.bufferSound("game.win");
				
				WinnerDialog w = new WinnerDialog((JFrame)parentFrame, (Player)(m.parameters.firstElement()));
			}
			else if(m.type.equals("nextPlayer")) {
				updateInfoPanel();
				updateDPadPanel();
				updateAccusePanel();
				updateSuggestPanel();
				
				// Added by alex
				accuseCombo[SUSPECT_INDEX].setSelectedIndex(0);
				accuseCombo[WEAPON_INDEX].setSelectedIndex(0);
				accuseCombo[ROOM_INDEX].setSelectedIndex(0);
				
				suggestCombo[SUSPECT_INDEX].setSelectedIndex(0);
				suggestCombo[WEAPON_INDEX].setSelectedIndex(0);
				
				
				updateCardsPanel();
				
				// Disable user-input when AI player is active.
				if(gameController.getBoard().getCurrentPlayer().getPlayerType() > 0) {
					disableInterface();
					
				}
				else
					enableInterface();
				
			}
			else if(m.type.equals("suggestionOnLastTurn")) {
				updateInfoPanel();

			}
		}
	};
	
	private void disableInterface() {
		tabs.setEnabled(false);
	}

	private void enableInterface() {
		tabs.setEnabled(true);
	}

	/****************************************************************************
	 *	ACTION LISTENERS FOR PANEL FEATURES
	 *
	 ****************************************************************************
	 */
	
	
	/**
	 * Action listener for end turn
	 * 
	 */
	ActionListener endTurnButtonListener = new ActionListener() {

		public void actionPerformed(ActionEvent e) {
			Player currentPlayer = gameController.getBoard().getCurrentPlayer();
			
			SuggestReminder sr = null;
			if (currentPlayer.canSuggest() && currentPlayer.canSuggestHere()  && currentPlayer.isInteractive() == true){
				sr = new SuggestReminder(parentFrame, gameController);
				sr.show();
				
				if (sr.getInterestingData().equals("endGo"))
					gameController.directCommand("nextPlayer", null);
				
				else if (sr.getInterestingData().equals("suggest"))
					tabs.setSelectedIndex(3);
				
			}
			else
				gameController.directCommand("nextPlayer", null);
		}
	};
	
	/**
	 * ActionListener for the accuse Button
	 */     
	ActionListener accuseButtonListener = new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			String sName = (String)accuseCombo[SUSPECT_INDEX].getSelectedItem();
			String wName = (String)accuseCombo[WEAPON_INDEX].getSelectedItem();
			String rName = (String)accuseCombo[ROOM_INDEX].getSelectedItem();
			
			Player currentPlayer = gameController.getBoard().getCurrentPlayer();
			//CardCollection DCards = currentPlayer.getDetectivePad().getCardList();
			
			Vector holdAccuse = new Vector();
			holdAccuse.add(sName);
			holdAccuse.add(wName);
			holdAccuse.add(rName);
			
			
			// Calls winGame or removeInteractive in GC
			
			SoundEngine.bufferSound("notify.confirm");
			AccuseConfirmation  ac = new AccuseConfirmation(parentFrame,holdAccuse,gameController);
			ac.show();
			
			updateInfoPanel();
			updateAccusePanel();
			updateSuggestPanel();
			
			
		}	
	};
	
	/**
	 * ActionListener for the suggest Button
	 */        
	ActionListener suggestButtonListener = new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			try {
				Player currentPlayer = gameController.getBoard().getCurrentPlayer();
				CardCollection DCards = currentPlayer.getDetectivePad().getCardList();
				if(currentPlayer.canSuggestHere() == false) {
					//"You can't make a suggestion here."
				}
				else if(currentPlayer.isSuggestionOnLastTurn() == true) {
					// "You can't make multiple suggestions without leaving the room."
				}
				else if(currentPlayer.canSuggest() == true) {
					CardCollection gameCards = gameController.getBoard().getCardPack();
					
					Card suspect = gameCards.cardByName((String)suggestCombo[SUSPECT_INDEX].getSelectedItem());
					Card weapon = gameCards.cardByName((String)suggestCombo[WEAPON_INDEX].getSelectedItem());
					System.out.println("Toolbar: getting " + currentPlayer.getPosition().getID());
					System.out.println("In pad? " + gameCards.cardByName(currentPlayer.getPosition().getID()));
					
					Card room = gameCards.cardByName(currentPlayer.getPosition().getID());
					
					Player defendant = gameController.getBoard().getCharacter(suspect.getName());
					
					
					Vector suggestCards = new Vector();
					suggestCards.add(suspect.getName());
					suggestCards.add(weapon.getName());
					suggestCards.add(room.getName());
					
					
					Message accuseMessage = new Message();
					accuseMessage.parameters= suggestCards;
					
					SoundEngine.bufferSound("notify.confirm");
					
					SuggestionPreview  suggestionPreview = new SuggestionPreview(parentFrame,suggestCards,gameController);
					suggestionPreview.show();
					
					String feedback = (String) suggestionPreview.getInterestingData();
					
					if (!feedback.equals("yes")) {
						return;
					}
					
					
					/** Move the defendant into the room **/
					if(!currentPlayer.getCharacter().equals(suspect.getName())) {
						if(defendant != null) {
							Position oldRoom = defendant.getPosition();
							Position destination = currentPlayer.getPosition();
							
							Vector parameters = new Vector();
							parameters.add(destination);
							parameters.add(defendant);		// Who to move..
							gameController.directCommand( "movePlayer", parameters );
						}
					}

					//TODO: Find out why this code doesn't get called further down
					/** Mark off the player as having made a suggestion */
					Vector parameters = new Vector();
					parameters.add(currentPlayer);
					gameController.directCommand("setSuggestionOnLastTurn", parameters);
					
					
					System.out.println("Beginning candidate search!");
					Vector disproofInfo = findDisproveCandidate(suspect, weapon, room);
					Player playerCandidate = null;
					
					if(disproofInfo != null)
						playerCandidate = (Player)disproofInfo.firstElement();
					else {
						System.out.println("No candidate found!");
					}
					
					
					disproofReceived = false;
					Message suggestionAlertMessage = new Message();
					Vector params = new Vector();
					params.add(new SuggestionAlert(suspect, weapon, room, currentPlayer.getRealName()) );
					suggestionAlertMessage.parameters = params;
					suggestionAlertMessage.type = "suggestionAlert";
					
					if(disproofInfo != null) {
						suggestionAlertMessage.data = playerCandidate.getRealName();
					}
					else {
						suggestionAlertMessage.data = "";
						System.out.println("Relaying a " + suggestionAlertMessage + " with no candidate");
					}
					
					System.out.println("Relaying out suggestionAlert.");
					gameController.relayMessage(suggestionAlertMessage);
					

					System.out.println("[Toolbar:suggestButtonListener] In waiting loop");
					while ( disproofReceived == false ) {
						try {
							Thread.sleep(100);
						}
						catch(Exception ex) {
							
						}
					}
					System.out.println("[Toolbar:suggestButtonListener] Exit waiting loop");
					
					for(int i = 0; i < incomingDisproof.parameters.size(); i++) {
						System.out.println("[Toolbar:suggestButtonListener] Card shown."+((DisproofAlert)incomingDisproof.parameters.firstElement()).getCardShown());
					}
					
					DisproofAlert disproofAlert = (DisproofAlert)incomingDisproof.parameters.firstElement();
					
					System.out.println("[Toolbar:suggestButtonListener] Display SuggestionNotification");
					SuggestionNotification suggestionNotification = new SuggestionNotification(parentFrame, disproofAlert, gameController);
					suggestionNotification.setVisible(true);
					
					System.out.println("[Toolbar:suggestButtonListener] Exit waiting loop");
					
					
				}
				
				suggestButton.setEnabled(false);
				tabs.setSelectedIndex(0);
				
			}
			
			catch(Exception ee) {
				ee.printStackTrace();
			}
		}
   };
   
   /**
    * ItemListener used to update the player's real detective pad when there is a click
    */     
   ItemListener detectivePadUpdater = new ItemListener () {
   	public void itemStateChanged(ItemEvent e) {
   		if(ignoreDpadChanges == false) {
   			Player me = gameController.getBoard().getCurrentPlayer();
   			Vector parameters = new Vector();
   			parameters.add( ((JCheckBox)e.getItem()).getText() );
   			
   			if( ((JCheckBox)e.getItem()).isSelected() == true) {
   				gameController.directCommand("markDetectivePad", parameters);
   			}
   			else {
   				gameController.directCommand("unmarkDetectivePad", parameters);
   			}
   		}
   	}
   };
   
   /**
    * Used for roll dice button
    *
    */
   ActionListener diceRollButtonListener = new ActionListener() {
   	public void actionPerformed(ActionEvent e) {
   		Player currentPlayer = gameController.getBoard().getCurrentPlayer();
   		if(currentPlayer.canRoll() == true) {
   			gameController.directCommand("roll", null);
   			updateInfoPanel();
   		}
   	}
   	
   };
   
   ActionListener accusePanelComboListener = new ActionListener() {
   	public void actionPerformed(ActionEvent e) {
   		
   		int picIndex = -1;
   		
   		JComboBox cb1 = (JComboBox)e.getSource();
   		String name = (String)cb1.getSelectedItem();
   		String type= cb1.getName();
   		
   		
   		if(type.equals("suspect"))
   			picIndex = 0;
   		if (type.equals("weapon"))
   			picIndex = 1;
   		if (type.equals("room"))
   			picIndex = 2;
   		
   		changePic(name, picIndex, accusePicArray);
   		updateAccusePanel();
   	}
   };


  ActionListener suggestPanelComboListener = new ActionListener() {
  	public void actionPerformed(ActionEvent e) {
  		int picIndex = -1;
  		
  		JComboBox cb1 = (JComboBox)e.getSource();
  		String name = (String)cb1.getSelectedItem();
  		String type= cb1.getName();
  		
  		
  		if(type.equals("suspect"))
  			picIndex = 0;
  		if (type.equals("weapon"))
  			picIndex = 1;
  		if (type.equals("room"))
  			picIndex = 2;
  		
  		changePic(name, picIndex, suggestPicArray);
  		updateSuggestPanel();
  	}
  };
  
  /****************************************************************************
   *	BUILD PANELS FOR THE GAME
   *
   ****************************************************************************
   */
  
  /**
   * Generates the initial layout and data items for the detective notepad panel.
   *
   * @return JPanel containing the generated panel.
   *
   */
  private JPanel buildNotePadPanel() {
  	JPanel content = new JPanel();
  	content.setBorder ( BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), lookup("dpad_title") ) );
  	content.setLayout(new BorderLayout( ));
  	
  	Box suspectedItems = Box.createVerticalBox();
  	CardCollection cards = gameController.getBoard().getCardPack();
  	suspectCheck = new JCheckBox[cards.countCards()];
  	suspectText = new JTextField[cards.countCards()];
  	
  	ignoreDpadChanges = true;
  	
  	String lastType = "";
  	boolean addTitle = false;
  	
  	for(int i = 0; i < cards.countCards(); i++) {
  		
  		if(lastType.equals(""))
  			addTitle = true;
  		if(!lastType.equals(cards.cardAt(i).getType()))
  			addTitle = true;
  		
  		lastType = cards.cardAt(i).getType();
  		
  		Box row = Box.createHorizontalBox();
  		
  		if(addTitle == true) {
  			Box titleRow = Box.createHorizontalBox();
  			JLabel caption = new JLabel( lookup(lastType.toLowerCase()+"_plural") + " : -");
  			caption.setMaximumSize( new Dimension(230, 20) );
  			caption.setPreferredSize( new Dimension(230, 20) );
  			caption.setMinimumSize( new Dimension(230, 20) );
  			
  			titleRow.add( caption );
  			titleRow.add( new JSeparator(SwingConstants.HORIZONTAL) );
  			suspectedItems.add ( titleRow );
  		}
  		
  		suspectCheck[i] = new JCheckBox(cards.cardAt(i).getName());
  		suspectCheck[i].addItemListener( detectivePadUpdater );
  		
  		suspectCheck[i].setMaximumSize(new Dimension(120, 20));
  		suspectCheck[i].setPreferredSize(new Dimension(120, 20));
  		suspectCheck[i].setMinimumSize(new Dimension(120, 20));
  		
  		row.add ( suspectCheck[i] );
  		
  		suspectText[i] = new JTextField(15);
  		
  		suspectText[i].setMaximumSize(new Dimension(120, 20));
  		suspectText[i].setPreferredSize(new Dimension(120, 20));
  		suspectText[i].setMinimumSize(new Dimension(120, 20));
  		
  		row.add ( suspectText[i] );
  		
  		suspectedItems.add(row);
  		
  		addTitle = false;
  	}
  	
  	
  	JLabel dpadLabel = new JLabel(
  			formatString (lookup("dpad_summary")));
  	
  	dpadLabel.setFont(new Font("Arial", Font.BOLD, 12));
  	
  	Box header = Box.createVerticalBox();
  	header.add( dpadLabel, BorderLayout.NORTH );
  	header.add( Box.createVerticalStrut(10) );
  	header.add( new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.CENTER );
  	header.add( Box.createVerticalStrut(10) );
  	
  	
  	content.add(header, BorderLayout.NORTH);
  	content.add(suspectedItems, BorderLayout.CENTER);
  	
  	ignoreDpadChanges = false;
  	
  	return content;
  }
  
  
  /**
   * Generates the initial layout and data items for the info panel.
   *
   * @return JPanel containing the generated panel.
   *
   */
  private JPanel buildInfoPanel() {
  	Player currentPlayer = gameController.getBoard().getCurrentPlayer();
  	String infoMessage = formatString(lookup("info_summary"));
  	
  	JPanel content = new JPanel();
  	Box verticalContent = Box.createVerticalBox();
  	content.setBorder (BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), lookup("info_title") ));
  	content.setLayout (new BorderLayout());
  	
  	JLabel infoLabel = new JLabel();
  	
  	infoLabel.setText(infoMessage);
  	infoLabel.setFont( new Font( "Arial", Font.BOLD, 12) );
  	
  	content.add(infoLabel, BorderLayout.NORTH);
  	
  	// Set all info icons to be new CardImages
  	for (int i=0; i<4; i++)
  		infoIcons[i] = new CardImage("", "");
  	
  	
  	
  	// Current playing character's image
  	JPanel mPanel1 = new JPanel();  		
  	String cardName = currentPlayer.getCharacter();
  	cimagePlayer = new CardImage(getCardImage(cardName), cardName.toLowerCase());  		
  	mPanel1.add(cimagePlayer);
  	
  	// Current playing characters information
  	JPanel mPanel2 = new JPanel();      	
  	playingName = new JLabel(currentPlayer.getRealName());
  	playingName.setFont(( new Font( "Arial", Font.BOLD, 12) ));
  	playingChar = new JLabel(currentPlayer.getCharacter());
  	playingChar.setFont(( new Font( "Arial", Font.BOLD, 12) ));
  	
  	int cRef = gameController.getBoard().getPlayerIndex(currentPlayer);
  	playerColour = new JLabel("Colour : " + getColourIDByCharacter(currentPlayer.getCharacter()));

  	playerColour.setFont(new Font( "Arial", Font.BOLD, 12));
  	
  	playerColour.setForeground(getColourByName(currentPlayer.getCharacter()));
  	
  	String txtOutput = String.valueOf(currentPlayer.getMovesRemaining());
  	movesRemaining = new JLabel(txtOutput + " moves remaining.");
  	movesRemaining.setFont(( new Font( "Arial", Font.BOLD, 12) ));
  	
  	Box vertBox1 = Box.createVerticalBox();
  	vertBox1.add(playingName);
  	vertBox1.add(playingChar);
  	vertBox1.add(movesRemaining);
  	vertBox1.add(playerColour);
  	
  	mPanel2.add(vertBox1);
  	
  	Box hozBox1 = Box.createHorizontalBox();
  	hozBox1.add(mPanel1);
  	hozBox1.add(mPanel2);
  	
  	// Available move labels
  	Box hozBox2 = Box.createHorizontalBox();
  	Box vertBox2 = Box.createVerticalBox();
  	Box vertBox3 = Box.createVerticalBox();
  	
  	int count=0;
  	for (int i=0; i<4; i++) {
  		candoLabel[i] = new JLabel(" ");
  		candoLabel[i].setFont(( new Font( "Arial", Font.BOLD, 12) ));
  	}
  	vertBox2.add(infoIcons[0]);
  	vertBox2.add(infoIcons[1]);
  	vertBox2.add(infoIcons[2]);
  	vertBox2.add(infoIcons[3]);
  	
  	candoLabel[0].setText("   " + lookup("may_move") );
  	candoLabel[1].setText("   " + lookup("may_roll") );
  	candoLabel[2].setText("   " + lookup("may_suggest") );
  	candoLabel[3].setText("   " + lookup("may_accuse") );
  	
  	if (currentPlayer.canMove()) {
  		candoLabel[0].setEnabled(true);
  		infoIcons[0].changeCard(iconPath + "move.gif", "Move");
  	} else {
  		candoLabel[0].setEnabled(false);
  		infoIcons[0].changeCard(iconPath + "moved.gif", "Moved");
  	}
  	
  	
  	if (currentPlayer.canRoll()) {
  		candoLabel[1].setEnabled(true);
  		infoIcons[1].changeCard(iconPath + "roll.gif", "Roll");
  	} else {
  		candoLabel[1].setEnabled(false);
  		infoIcons[1].changeCard(iconPath + "rolled.gif", "Rolled");
  	}
  	
  	if (currentPlayer.canSuggestHere()) {
  		candoLabel[2].setEnabled(true);
  		infoIcons[2].changeCard(iconPath + "suggest.gif", "Suggest");
  	} else {
  		candoLabel[2].setEnabled(false);
  		infoIcons[2].changeCard(iconPath + "suggested.gif", "Suggested");
  	}
  	
  	if (currentPlayer.isInteractive()) {
  		candoLabel[3].setEnabled(true);
  		infoIcons[3].changeCard(iconPath + "accuse.gif", "Accuse");
  	} else {
  		candoLabel[3].setEnabled(false);
  		infoIcons[3].changeCard(iconPath + "accused.gif", "Accused");
  	}
  	
  	vertBox3.add(candoLabel[0]);
  	vertBox3.add(Box.createVerticalStrut(15));
  	vertBox3.add(candoLabel[1]);
  	vertBox3.add(Box.createVerticalStrut(15));
  	vertBox3.add(candoLabel[2]);
  	vertBox3.add(Box.createVerticalStrut(15));
  	vertBox3.add(candoLabel[3]);
  	
  	hozBox2.add(vertBox2);
  	hozBox2.add(vertBox3);
  	
  	JPanel mPanel3 = new JPanel();
  	mPanel3.add(hozBox2);
  	
  	// Two dice panels with images
  	JPanel mPanel4 = new JPanel();
  	int dice1 = gameController.getBoard().getDiceValue(1);
  	if (dice1 == -1) dice1 = 1;
  	diceImage1 = new CardImage(getDicePath(dice1), getDicePath(dice1));
  	mPanel4.add(diceImage1);
  	
  	JPanel mPanel5 = new JPanel();
  	int dice2 = gameController.getBoard().getDiceValue(2);
  	if (dice2 == -1) dice2 = 1;
  	diceImage2 = new CardImage(getDicePath(dice2), getDicePath(dice2));
  	mPanel5.add(diceImage2);
  	
  	Box hozBox3 = Box.createHorizontalBox();
  	hozBox3.add(mPanel4);
  	hozBox3.add(mPanel5);
  	
  	// Roll dice button code
  	JPanel mPanel6 = new JPanel();
  	rollDiceButton = new JButton(lookup("roll_dice"));
  	rollDiceButton.addActionListener(diceRollButtonListener);
  	rollDiceButton.setPreferredSize(new Dimension(200,25));
  	rollDiceButton.setMinimumSize(new Dimension(200,25));
  	rollDiceButton.setMaximumSize(new Dimension(200,25));
  	mPanel6.add(rollDiceButton);
  	
  	
  	// End Go button code
  	JPanel mPanel7 = new JPanel();
  	endGo = new JButton(lookup("end_turn"));
  	endGo.addActionListener(endTurnButtonListener);
  	
  	verticalContent.add(new JSeparator(SwingConstants.HORIZONTAL));      	
  	verticalContent.add(hozBox1);
  	verticalContent.add(new JSeparator(SwingConstants.HORIZONTAL));
  	verticalContent.add(mPanel3);
  	verticalContent.add(new JSeparator(SwingConstants.HORIZONTAL));  	
  	verticalContent.add(hozBox3);
  	verticalContent.add(mPanel6);
  	verticalContent.add(new JSeparator(SwingConstants.HORIZONTAL));
  	verticalContent.add(mPanel7);
  	content.add(verticalContent,BorderLayout.CENTER);
  	
  	content.add(endGo, BorderLayout.SOUTH);
  	
  	return content;  	
  }

  
  /**
   * Generates the initial layout and data items for the cards panel.
   * 
   * @return JPanel containing the generated panel.
   *  
   */
	private JPanel buildCardsPanel() {
		JPanel content = new JPanel();
		content.setBorder(BorderFactory.createTitledBorder(BorderFactory
				.createEtchedBorder(), lookup("cards_title")));
		content.setLayout(new BorderLayout());

		// Top Panel
		Box overallBox = Box.createVerticalBox();
		JPanel topPanelOverall = new JPanel();
		topPanelOverall.setLayout(new GridLayout(2, 1));
		JPanel topPanel = new JPanel();

		JLabel cardsLabel = new JLabel(formatString(lookup("cards_summary")));
		cardsLabel.setFont(new Font("Arial", Font.BOLD, 12));

		topPanel.add(cardsLabel);
		topPanelOverall.add(topPanel);
		topPanelOverall.add(new JSeparator(SwingConstants.HORIZONTAL));

		overallBox.add(topPanelOverall);
		overallBox.add(Box.createVerticalStrut(0));
		content.add(overallBox, BorderLayout.NORTH);

		// Bottom Panel
		JPanel bottomPanel = new JPanel();

		GridBagLayout gridbag = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();

		int currentRow = 0;

		c.gridx = 0;

		int gameCards = gameController.getBoard().getCardPack().countCards();
		int cardsPerPlayer = ((gameCards - 3) / 3) + ((gameCards - 3) % 3);
		final int cardsPerRow = 2;

		c.ipadx = 10;
		c.ipady = 10;
		if (cardsPerRow == 3) {
			c.ipadx = 1;
			c.ipady = 1;
		}

		System.out.println(cardsPerPlayer);

		cardsHeld = new CardImage[cardsPerPlayer];

		for (int i = 0; i < cardsPerPlayer; i++) {
			cardsHeld[i] = new CardImage("" + i, "" + i);
			c.weightx = 1;
			c.weighty = 1;

			c.gridx++;
			c.fill = GridBagConstraints.BOTH;
			if (i % cardsPerRow == 0) {
				c.gridy = ++currentRow;
				c.gridx = 0;
			}
			gridbag.setConstraints(cardsHeld[i], c);
			bottomPanel.add(cardsHeld[i]);
		}

		bottomPanel.setLayout(gridbag);
		JScrollPane cardView = new JScrollPane(bottomPanel);
		cardView.setPreferredSize(new Dimension(200, 450));

		content.add(cardView, BorderLayout.CENTER);

		return content;
	}
  
  /**
   * Generates the initial layout and data items for the suggest panel.
   * 
   * @return JPanel containing the generated panel.
   *  
   */
  private JPanel buildSuggestPanel() {
  	JPanel content = new JPanel();
  	content.setBorder ( BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), lookup("suggest_title") ) );
  	content.setLayout (new BorderLayout());
  	
  	String suggestInfo = formatString(lookup("suggest_summary"));
  	
  	//contains pictures
  	suggestPicArray = new CardImage[3];
  	
  	CardCollection cards = gameController.getBoard().getCardPack();
  	
  	//List of names
  	Vector suspects = gameController.getBoard().getCardList("Suspect");
  	Vector rooms = gameController.getBoard().getCardList("Room");
  	Vector weapons = gameController.getBoard().getCardList("Weapon");
  	
  	
  	suggestCombo = new JComboBox[2];
  	
  	suggestRoomLabel = new JLabel("No Room");
  	
  	String comboLabels[] = new String[] {"Suspect", "Weapon"};
  	suggestCombo[0] = new JComboBox(suspects);
  	suggestCombo[0].setName("suspect");
  	suggestCombo[1] =  new JComboBox(weapons);
  	suggestCombo[1].setName("weapon");
  	
  	
  	String cardName = "";
  	
  	
  	for (int i = 0; i < suggestCombo.length; i++) {
  		suggestCombo[i].setMaximumSize(new Dimension(100,20));
  		suggestCombo[i].addActionListener(suggestPanelComboListener);
  		suggestCombo[i].setSelectedIndex(0);
  		cardName = ((String) accuseCombo[i].getSelectedItem());
  		//suggestPicArray[i] = new CardImage(getCardImage(cardName), cardName);
  		
  		if (new File(cardImagePath + cardName.toLowerCase() + ".gif").exists()) {
  		   suggestPicArray[i]= new CardImage(getCardImage(cardName), cardName);
  		}
	    else {
	       suggestPicArray[i]= new CardImage(getCardImage("no_room"), cardName);
	    }
  		 
  		
  	}
  	
  	suggestPicArray[ROOM_INDEX] = new CardImage(getCardImage("no_room"), "No room");
  	
  	Box top = Box.createVerticalBox();
  	JLabel intro = new JLabel(suggestInfo);
  	intro.setFont( new Font( "Arial", Font.BOLD, 12) );
  	top.add( intro );
  	top.add( Box.createVerticalStrut(5) );
  	top.add( Box.createVerticalGlue() );
  	top.add( new JSeparator(SwingConstants.HORIZONTAL) ); 
  	
  	Box suggest = Box.createVerticalBox();
  	
  	for(int i=0; i<suggestCombo.length; i++) {
  		Box inner = Box.createHorizontalBox();
  		Box pic = Box.createVerticalBox();
  		JPanel label =new JPanel();
  		Box borderBox = Box.createVerticalBox();
  		pic.add(suggestPicArray[i]);
  		
  		label.add(Box.createVerticalStrut(100));
  		label.add(suggestCombo[i]);
  		inner.add(Box.createHorizontalStrut(5));
  		
  		inner.add(pic);
  		inner.add(Box.createHorizontalStrut(20));
  		inner.add(label);
  		inner.add(Box.createHorizontalStrut(5));
  		
  		
  		
  		borderBox.add(inner);
  		
  		borderBox.setBackground(cardBorderColours[i]);
  		borderBox.setBorder ( BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), suggestCombo[i].getName().toUpperCase() )  );
  		
  		suggest.add(borderBox);
  		
  	}
  	
  	
  	
  	//room Display
  	
  	Box roomBox = Box.createHorizontalBox();
  	Box roomPic = Box.createVerticalBox();
  	JPanel roomLabel = new JPanel();
  	
  	roomPic.add(suggestPicArray[ROOM_INDEX]);
  	
  	roomLabel.add(Box.createVerticalStrut(100));
  	roomLabel.add(suggestRoomLabel);
  	
  	roomBox.add(Box.createHorizontalStrut(5));
  	roomBox.add(roomPic);
  	roomBox.add(Box.createHorizontalStrut(20));
  	roomBox.add(roomLabel);
  	roomBox.add(Box.createHorizontalStrut(58));
  	
  	Box overallRoom = Box.createVerticalBox();
  	overallRoom.add(roomBox);
  	overallRoom.setBorder ( BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "ROOM" )  );
  	overallRoom.setBackground(cardBorderColours[ROOM_INDEX]);
  	
  	suggest.add(overallRoom);
  	
  	suggestButton = new JButton(lookup("suggest_button"));
  	suggestButton.addActionListener(suggestButtonListener);
  	suggestButton.setEnabled(false);
  	
  	content.add(top,"North");
  	content.add(suggestButton,BorderLayout.SOUTH);
  	content.add(suggest,"Center");
  	
  	
  	return content;	
  	
  }
  
  /**
   * Generates the initial layout and data items for the accuse panel.
   *
   * @return JPanel containing the generated panel.
   *
   */
  synchronized private JPanel buildAccusePanel() {
  	JPanel content = new JPanel();
  	content.setBorder ( BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), lookup("accuse_title") ));
  	content.setLayout (new BorderLayout());
  	
  	String accuseInfo = formatString(lookup("accuse_summary")); 
  	
  	accuseCombo = new JComboBox[3];
  	
  	Vector suspects = gameController.getBoard().getCardList("Suspect");
  	Vector rooms = gameController.getBoard().getCardList("Room");
  	Vector weapons = gameController.getBoard().getCardList("Weapon");
  	
  	
  	
  	accuseCombo[SUSPECT_INDEX] = new JComboBox(suspects);
  	accuseCombo[SUSPECT_INDEX].setName("suspect");
  	
  	accuseCombo[WEAPON_INDEX] =  new JComboBox(weapons);
  	accuseCombo[WEAPON_INDEX].setName("weapon");
  	
  	accuseCombo[ROOM_INDEX] =  new JComboBox(rooms);
  	accuseCombo[ROOM_INDEX].setName("room");
  	
  	accusePicArray = new CardImage[3];
  	
  	String cardName = "";
  	
  	for (int i = 0; i < accuseCombo.length; i++) {
  		accuseCombo[i].setMaximumSize(new Dimension(100, 20));
  		accuseCombo[i].addActionListener(accusePanelComboListener);
  		
  		cardName = (String) accuseCombo[i].getSelectedItem();
  		
  		if (new File(cardImagePath + cardName.toLowerCase() + ".gif").exists())
  			accusePicArray[i]= new CardImage(getCardImage(cardName), cardName);
  		
  		else 
  			accusePicArray[i]= new CardImage(cardImagePath+"no_room.gif", cardName);
  	}
  	
  	Box top = Box.createVerticalBox();
  	JLabel intro = new JLabel(accuseInfo);
  	intro.setFont( new Font( "Arial", Font.BOLD, 12) );
  	top.add( intro );
  	top.add( Box.createVerticalStrut(5) );
  	top.add( Box.createVerticalGlue() );
  	top.add( new JSeparator(SwingConstants.HORIZONTAL) ); 
  	
  	Box accuse = Box.createVerticalBox();
  	
  	for(int i=0; i<accusePicArray.length; i++) {
  		Box inner = Box.createHorizontalBox();
  		Box pic = Box.createVerticalBox();
  		JPanel label = new JPanel();
  		Box borderBox = Box.createVerticalBox();
  		pic.add(accusePicArray[i]);
  		
  		label.add(Box.createVerticalStrut(100));
  		label.add(accuseCombo[i]);
  		inner.add(Box.createHorizontalStrut(5));
  		inner.add(pic);
  		inner.add(Box.createHorizontalStrut(20));
  		inner.add(label);
  		inner.add(Box.createHorizontalStrut(5));
  		
  		
  		
  		borderBox.add(inner);
  		
  		borderBox.setBackground(cardBorderColours[i]);
  		borderBox.setBorder ( BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),accuseCombo[i].getName().toUpperCase()  )  );
  		
  		
  		accuse.add(borderBox);
  		
  		
  	}
  	
  	
  	accusePreviewLabel = new JLabel("");
  	
  	accuseButton = new JButton(lookup("accuse_button"));
  	accuseButton.addActionListener(accuseButtonListener);
  	
  	content.add(top,BorderLayout.NORTH);
  	content.add(accuse, BorderLayout.CENTER);
  	content.add(accuseButton, BorderLayout.SOUTH);
  	
  	
  	return content;
  	
  }
  
  
  /****************************************************************************
   *	UPDATE PANELS WITH DATA FOR CURRENT (EVENT/TURN)
   *
   ****************************************************************************
   */
  private void updateAccusePanel() {
  	Player currentPlayer = gameController.getBoard().getCurrentPlayer();
  	Position cPlayerPos = currentPlayer.getPosition();
  	
  	String suspectName = (String)accuseCombo[SUSPECT_INDEX].getSelectedItem();
  	String weaponName = (String)accuseCombo[WEAPON_INDEX].getSelectedItem();
  	String roomName = (String)accuseCombo[ROOM_INDEX].getSelectedItem();
  	

	accuseButton.setEnabled(currentPlayer.isInteractive());

  	/*
  	if (currentPlayer.isInteractive()) {
  		accusePreviewLabel.setText(
  				addArguments(lookup("accuse_message", DEFAULT_GROUP), new String[] {suspectName, weaponName, roomName}));
  		
  		accuseButton.setEnabled(true);
  	}
  	else {
  		accusePreviewLabel.setText("<html><body><br></body></html>");
  		accuseButton.setEnabled(false);
  	}*/
  	repaint();
  }
  
  /**
   * Updates the suggestion panel
   *
   */
  synchronized private void updateSuggestPanel() {
  	Player currentPlayer = gameController.getBoard().getCurrentPlayer();
  	Position cPlayerPos = currentPlayer.getPosition();
  	
  	
  	
  	if(suggestButton != null)
  		if (cPlayerPos instanceof Room) {
  			changePic(cPlayerPos.getID(), ROOM_INDEX, suggestPicArray);
  			suggestRoomLabel.setText(cPlayerPos.getID());
  			if(gameController.getBoard().getCurrentPlayer().isSuggestionOnLastTurn() == true) {
  				suggestButton.setEnabled(false);
  			}
  			
  			else{
  				suggestButton.setEnabled(true);
  				String sName = (String)suggestCombo[SUSPECT_INDEX].getSelectedItem();
  				String wName = (String)suggestCombo[WEAPON_INDEX].getSelectedItem();
  				
  			}
  		}
  		else {
  			changePic("no_room", ROOM_INDEX, suggestPicArray);
  			suggestRoomLabel.setText("No Room");
  			suggestButton.setEnabled(false);
  		}
  	
  	if(currentPlayer != null && suggestButton != null)
  		if(currentPlayer.isInteractive() == false)
  			suggestButton.setEnabled(false);
  		
  		
  	repaint();
  	
  }

  /**
   * Updates the cards panel for the current player
   *
   */  
  private void updateCardsPanel() {
  	
  	Player currentPlayer = gameController.getBoard().getCurrentPlayer();
  	CardCollection cards = currentPlayer.getCards();
  	String currentCard = "";
  	ImageIcon cardImage = null;
  	
  	if(cards == null || currentPlayer == null )
  		return;
  	
  	int cardIndex = 0;
  	String []types = {"Suspect","Weapon","Room"};
  	
  	for(int i =0;i<types.length;i++) {
  		for(int j =0; j < cards.countCards(); j++) {
  			//System.out.println(cards.cardAt(j).getType());
  			if(cards.cardAt(j).getType().equals(types[i])) {
  		  		// Get the current card
  		  		currentCard = cards.cardAt(j).getName();
  		  		
  		  		// Find if an image was loaded before for it
  		  		cardImage = getCardImage(currentCard);
  		  		
  		  		// If the card was found, pass it to the card image
  		  		if(cardImage != null) {
  		  			cardsHeld[cardIndex].changeCard(
  		  					cardImage, currentCard);
  		  		}
  		  		else {
  		  			// Pass the name to the card image
  		  			cardsHeld[cardIndex].changeCard(currentCard);
  		  		}
  		  		
  		  		cardIndex++;
  			}
  		}
  	}
  	/*
  	for(cardIndex = 0; cardIndex < cards.countCards(); cardIndex++) {
  		
  		//Too many cards to be shown  		
  		if(cardIndex >= cardsHeld.length) {
  			break;
  		}
  		
  		// Get the current card
  		currentCard = cards.cardAt(cardIndex).getName();
  		
  		// Find if an image was loaded before for it
  		cardImage = getCardImage(currentCard);
  		
  		// If the card was found, pass it to the card image
  		if(cardImage != null) {
  			cardsHeld[cardIndex].changeCard(
  					cardImage, 
					currentCard);
  		}
  		else {
  			// Pass the name to the card image
  			cardsHeld[cardIndex].changeCard(
  					currentCard);
  		}
  	}*/
  	
  	// For the remaining cards, set a blank card
  	
  	for(; cardIndex < cardsHeld.length; cardIndex++) {
  		cardsHeld[cardIndex].changeCard(" ", "");
  	}
  	
  }
  


  /**
   * Updates the info panel so the information is correct for the current player
   *
   */  
  private void updateInfoPanel() {
		Player currentPlayer = gameController.getBoard().getCurrentPlayer();
		String iconPath = "Resources/Icons/";
		
		if(new File(iconPath + "moved.gif").exists() == false)
			iconPath = "../../Resources/Icons/";
		
		if (currentPlayer.isInteractive() == true
				&& currentPlayer.hasRolled() == false
				&& currentPlayer.getPlayerType() == 0) {
			rollDiceButton.setEnabled(true);
		} else {
			rollDiceButton.setEnabled(false);
		}

		if (currentPlayer.getPlayerType() >= 1) {
			endGo.setEnabled(false);
		} else {
			endGo.setEnabled(true);
		}

		playingName.setText(currentPlayer.getRealName());
		playingChar.setText(currentPlayer.getCharacter());
		String txtOutput = String.valueOf(currentPlayer.getMovesRemaining());
		movesRemaining.setText(addArguments(lookup("moves_remaining"),
				new String[] { txtOutput }));
		int cRef = gameController.getBoard().getPlayerIndex(currentPlayer);
		playerColour.setText(addArguments(lookup("your_colour"),
				new String[] { getColourIDByCharacter(currentPlayer.getCharacter())  }));
		
		playerColour.setForeground(getColourByName(currentPlayer.getCharacter()));

		int dice1 = gameController.getBoard().getDiceValue(1);
		if (dice1 == -1)
			dice1 = 1;
		diceImage1.changeCard(getDicePath(dice1), getDicePath(dice1));

		int dice2 = gameController.getBoard().getDiceValue(2);
		if (dice2 == -1)
			dice2 = 1;
		diceImage2.changeCard(getDicePath(dice2), getDicePath(dice2));

		String cardName = currentPlayer.getCharacter();
		cimagePlayer.changeCard(getCardImage(cardName), cardName.toLowerCase());

		int count = 0;
		if (currentPlayer.isInteractive() == true && currentPlayer.canMove()) {
			candoLabel[0].setEnabled(true);
			infoIcons[0].changeCard(iconPath + "move.gif", "Move");
			candoLabel[0].setText("   " + lookup("may_move"));
			count++;
		} else {
			candoLabel[0].setEnabled(false);
			infoIcons[0].changeCard(iconPath + "moved.gif", "Moved");
		}

		if (currentPlayer.isInteractive() == true && currentPlayer.canRoll()) {
			candoLabel[1].setEnabled(true);
			infoIcons[1].changeCard(iconPath + "roll.gif", "Roll");
			candoLabel[1].setText("   " + lookup("may_roll"));
			count++;
		} else {
			candoLabel[1].setEnabled(false);
			infoIcons[1].changeCard(iconPath + "rolled.gif", "Rolled");
		}

		if (currentPlayer.isInteractive() == true && (currentPlayer.canSuggestHere() && currentPlayer.canSuggest())) {
			candoLabel[2].setEnabled(true);
			infoIcons[2].changeCard(iconPath + "suggest.gif", "Suggest");
			candoLabel[2].setText("   " + lookup("may_suggest"));
			count++;
		} else {
			candoLabel[2].setEnabled(false);
			infoIcons[2].changeCard(iconPath + "suggested.gif", "Suggested");
		}

		if (currentPlayer.isInteractive() && gameController.getBoard().getGameFinished() == false) {
			candoLabel[3].setEnabled(true);
			infoIcons[3].changeCard(iconPath + "accuse.gif", "Accuse");
			candoLabel[3].setText("   " + lookup("may_accuse"));
			count++;
		} else {
			candoLabel[3].setEnabled(false);
			infoIcons[3].changeCard(iconPath + "accused.gif", "Accused");
		}

		repaint();
	}  
  
  /**
   * Updates the detective pad cards for the current player
   *  
   */  
  private void updateDPadPanel() {
  	CardCollection cards = gameController.getBoard().getCurrentPlayer().getDetectivePad().getCardList();

  	//tickedComboBox.setCardCollection(player.getDetectivePad().getCardList()); 
  	
  	for(int i = 0; i < cards.countCards(); i++) {
  		if(cards.cardAt(i).isEliminated() == true) {
  			if(suspectCheck[i].isSelected() == false)
  				suspectCheck[i].setSelected(true);
  		}
  		else
  			if(suspectCheck[i].isSelected() == true)
  				suspectCheck[i].setSelected(false);
  			
  	}
  }


  /****************************************************************************
   *	CONSTRUCT PANELS AND POSITION
   *
   ****************************************************************************
   */
  
  /**
   * Constructor for the toolbar and add panels to a JTabbedPane.
   *
   * @param gameConfig The config class used for the current game.
   * @param controller A pointer to the gameController.
   * @param parentFrame required for displaying JDialogs with the model option ( so they become the dominant window )
   *
   */
  public Toolbar(CluedoConfig gameConfig, GameController gameController, JFrame parentFrame) {
  	this.gameController = gameController;
  	this.gameConfig = gameConfig;
  	this.parentFrame = parentFrame;
  	
  	loadBufferedImages();
  	readTokenColours();
  	assignRemainingColours(gameController.getBoard().getPlayers(), gameController);

  	
  	// Make sure that we listen for events from the game controller.
  	gameController.bindListener(cluedoListen);
  	
  	// Create a new empty JTabbedPane
  	tabs = new JTabbedPane();
  	
  	// Get the panels ready to go onto the tabs
  	JPanel infoPanel = buildInfoPanel();
  	JPanel cardsPanel = buildCardsPanel();
  	JPanel notePanel = buildNotePadPanel();
  	JPanel accusePanel = buildAccusePanel();
  	JPanel suggestPanel = buildSuggestPanel();
  	
  	
  	// Add the tabs created into the JTabbedPane
  	tabs.addTab(lookup("info_panel"), infoPanel);	
  	tabs.addTab(lookup("cards_panel"), cardsPanel);
  	tabs.addTab(lookup("dpad_panel"), notePanel);
  	tabs.addTab(lookup("suggest_panel"), suggestPanel);
  	tabs.addTab(lookup("accuse_panel"), accusePanel);
  	
  	setLayout(new BorderLayout());
  	add(tabs, BorderLayout.CENTER);
  	
//  	setSize(280, 520);
  }
  
  
  /****************************************************************************
   *	FUNCTIONS AND CODE FOR PROCESSING DATA FROM PANELS
   *
   ****************************************************************************
   */
  
  /**
   *  Changes the picture of the JLabel at the picIndex in the picArray,
   *  used to update the image above the ComboBoxes on Suggest Panel / Accuse Panel.
   *
   *  @param picName
   *  Name of the picture.
   *
   *  @param picIndex
   *  The index in picArray
   *
   *  @param picArray
   *  The array that contains the pictures
   *
   */
  private void changePic(String cardName, int picIndex, CardImage[] picArray) {
  	String fileName = cardImagePath + cardName.toLowerCase() + ".gif";
  	
  	if(picArray[picIndex] != null) {
  		ImageIcon bufferedCard = getCardImage(cardName);
  		
  		if(bufferedCard != null && picArray[picIndex] != null) {
  			picArray[picIndex].changeCard(bufferedCard, cardName);
  		}
  		else {
  			picArray[picIndex].changeCard(cardName, cardName);
  		}
  	}
  }
  
  
  
  public Vector findDisproveCandidate( Card who, Card what, Card where ) {
  	Vector results = new Vector();
  	
  	String output = "";
  	Player playerWithCard = null;
  	Vector cardsFound = new Vector();
  	
  	Player currentPlayer = gameController.getBoard().getCurrentPlayer();
  	
  	
  	// Call who into where.
  	
  	Player defendant = gameController.getBoard().getCharacter(who.getName());
  	
  	if(!currentPlayer.getCharacter().equals(who.getName())) {
  		if(defendant != null) {
  			Position oldRoom = defendant.getPosition();
  			Position destination = currentPlayer.getPosition();
  			
  			Vector parameters = new Vector();
  			parameters.add(destination);
  			parameters.add(defendant);		// Who to move..
  			gameController.directCommand( "movePlayer", parameters );
  		}
  	}
  	
  	// Search all players for a card.
  	
  	
  	playerWithCard = null;
  	cardsFound = new Vector();
  	
  	// Order the players so we can scan through and check who has cards in the right order.
  	Vector playersToParse = arrangePlayersBy(currentPlayer);
  	
  	for(int i = 0; i < playersToParse.size(); i++) {
  		playerWithCard = (Player)playersToParse.elementAt(i);
  		if(playerWithCard != currentPlayer) {
  			if(playerWithCard.hasCard(who))
  				cardsFound.add(who);
  			if(playerWithCard.hasCard(what))
  				cardsFound.add(what);
  			if(playerWithCard.hasCard(where))
  				cardsFound.add(where);
  			if(cardsFound.size() > 0)
  				break;
  		}
  	}
  	
  	if(cardsFound.size() > 0) {
  		output += "+" +playerWithCard.getRealName() + " has the following relevant cards : -\n ";
  		for(int i = 0; i < cardsFound.size(); i++) {
  			output += ((Card)cardsFound.elementAt(i)).getName() + " ";
  		}
  		//gameConfig.setDisproveMode(true);
  	}
  	else {
  		output += "Unable to disprove the suggestion.";
  	}			
  	
  	System.out.println(output);
  	
  	results.add(playerWithCard);
  	results.add(cardsFound);
  	
  	if(cardsFound.size() == 0)
  		return null;
  	
  	return results;
  }
  
  
  
  
  /**
   * Returns a buffered ImageIcon representing a card's image.
   *
   * @param cardName Name of the card you want to retrieve.
   */
  private ImageIcon getCardImage(String cardName) {
      ImageIcon icon = null;
      
      try {
          icon = (ImageIcon)bufferedCardImages.get(cardName);
      }
      catch(Exception e) {
          icon = null;
      }

      return icon;
  }
  
  /**
   * Loads images into a hash table with O(1) reference, see getCardImage(str) for
   * accessing loaded files.
   *
   */  
  private void loadBufferedImages() {
  	long start = System.currentTimeMillis();
  	Cluedo.Game.CardCollection gameCards = gameController.getBoard().getCardPackLink();
  	String cardName = "";
  	ImageIcon cardIcon = null;
  	
  	for(int i = 0; i < gameCards.countCards(); i++) {
  		cardName = gameCards.cardAt(i).getName();
  		cardIcon = null;
  		if(new File(cardImagePath + cardName.toLowerCase() + ".gif").exists() == true) {
  			cardIcon = new ImageIcon(cardImagePath + cardName.toLowerCase() + ".gif");
  		
  			if(cardIcon != null)
  			    bufferedCardImages.put(cardName, cardIcon);
  		}
  	}
  	
  	cardName = "no_room";
  	
  	bufferedCardImages.put("no_room", new ImageIcon(cardImagePath + cardName.toLowerCase() + ".gif"));
  	
  	long end = System.currentTimeMillis();
  	System.out.println("[Toolbar:loadBufferedImages] buffered " +bufferedCardImages.size() + "/"+ gameCards.countCards() + " images, in (" + (end-start) + ") ms.");
  	
  }
  
  private Vector arrangePlayersBy(Player currentPlayer) {
  	Vector players = new Vector();
  	int playerPosition = gameController.getBoard().getPlayerIndex(currentPlayer);
  	Vector livePlayers = gameController.getBoard().getPlayers();
  	
  	// Add all elements after the player
  	for(int i = playerPosition + 1; i < livePlayers.size(); i++)
  		players.add(livePlayers.elementAt(i));
  	// Add all elements before the player
  	if(!( playerPosition == 0)) 
  		for(int i = 0; i < playerPosition; i++)
  			players.add(livePlayers.elementAt(i));
  	
  	return players;
  	
  }
  
  /**
   * Marks a card cardName as eliminated on the detective pad of the current player.
   * @cardName
   * Name of card to eliminate
   *
   */
  private void markPlayerCard(String cardName) {
  	Vector parameters = new Vector();
  	parameters.add( cardName );
  	gameController.directCommand("markDetectivePad", parameters);
  }
  
  private String getDicePath(int value) {
  	return "./Resources/dice/" + value + ".png";
  }
  
  
  /**
   * 
   *  			Code for string functions
   * 
   *
   */
  
  
/**
 * Get a string for a specified function from the language pack
 * using default group. 
 */
  private static String lookup(String function) {
  	return LanguagePack.getString(function, DEFAULT_GROUP);
  }
  
  /**
   * Get a string for a specified function from the language pack
   * using specified group. 
   */
  private static String lookup(String function, String group) {
  	return LanguagePack.getString(function, group);
  }
  
  
	/**
	 * Adds relevant arguments to string from String array 
	 * 
	 * @param string
	 * @param names2
	 * @return
	 */
	private static String addArguments(String string, String[] names2) {
		for(int i=0;i<names2.length;i++)
			string = string.replaceAll("%"+(i+1), names2[i]);
		if(string.indexOf("@@") > -1) {
			string = addBreaks(string);
		}
		return string;
	}
	
	
	/**
	 * @param string
	 * @return
	 */
	private static String addBreaks(String string) {
		string = string.replaceAll("@@", "<br>");
		string = Cluedo.API.Constants.HTML_ON + string + Cluedo.API.Constants.HTML_OFF;
		return string;
	}
  
  /**
   * Used to generate JLabels with line-breaks or additional html, in a user-transparent way
   *
   */
  private String formatString(String data) {
  	String output = data;
  	output = output.replaceAll("@@", Cluedo.API.Constants.HTML_NEWLINE);
  	output = output.replaceAll("\n", Cluedo.API.Constants.HTML_NEWLINE);
  	if(data.indexOf("\n") >=0 || data.indexOf("@@") >=0)
  		output = Cluedo.API.Constants.HTML_ON + output + Cluedo.API.Constants.HTML_OFF;

  	return output;
  }

  
  
/**
 * 
 *  			Code for finding piece colours
 * 
 *
 */
  
	/**
	 * Read from external file the preferred colour mappings for  
	 * characters
	 *
	 */
  public static void readTokenColours() {
      String line = "";
      String parts[];
      try {
          BufferedReader colours = new BufferedReader(new FileReader("Resources/Config/default.colours"));
          
          while((line = colours.readLine()) != null) {
              if(!line.startsWith("#")) {
                  parts = line.split("=");
                  if(parts.length == 2) {
                      nameColourMappings.put(parts[0].trim(), parts[1].trim());
                  }
                  
              }
          }
      }
      catch(Exception e) {
      }
      System.out.println("\tNames read: "+nameColourMappings.size());
  }
  
  /**
   * Given a list of players this will assign colours to those 
   * who still require colours.
   *  
   * @param players
   * @param gc
   */
  public static void assignRemainingColours(Vector players, GameController gc) {
      ArrayList taken = getUsedColours(gc);
      ArrayList lostCharacters = new ArrayList();
      
      for(int j = 0;j<players.size();j++) {
          if(getColourByName(((Player) players.get(j)).getCharacter())==null) {
              lostCharacters.add((String)((Player) players.get(j)).getCharacter());
          }
      }
      
      Object leftOver[] = colourMappings.keySet().toArray();
      
      int charIndex = 0;
      
      for(int i=0;i<leftOver.length && charIndex < lostCharacters.size();i++) {
          if(listContains( taken, ((String)leftOver[i])) == false) {
              nameColourMappings.put((String)lostCharacters.get(charIndex), leftOver[i]);
              //System.out.println("\t"+(String)lostCharacters.get(charIndex)+" gets " + leftOver[i]);
              charIndex++;
          }
      }
      
  }
  /**
   * Whether a list contains a certain String
   * 
   * @param taken
   * @param string
   * @return true if contained, else false
   */
  private static boolean listContains(ArrayList taken, String string) {
      for(int i=0;i<taken.size();i++) {
          if(((String)taken.get(i)).equals(string))
              return true;
      }
      return false;
  }

  /**
   * Finds any colours allocated to players. 
   * 
   * @param gc
   * @return
   */
  public static ArrayList getUsedColours(GameController gc) {
      ArrayList a = new ArrayList();
      Object[] keys = nameColourMappings.keySet().toArray();
      
      for(int i=0;i<keys.length;i++) {
          if(gc.getBoard().getCharacter((String)keys[i]) != null) {
              a.add( nameColourMappings.get((String)keys[i]) );
              //System.out.println( "used: " + nameColourMappings.get((String)keys[i]) + " " + (String)keys[i]);
          }
      }

      return a;
  }
  
  public static String getColourIDByCharacter(String character) {
      String ret;
      try {
          ret = (String)nameColourMappings.get(character);
      }
      catch(Exception e) {
          return null;    
      }
      return ret;
  }
  
  public static Color getColourByName(String name) {
      Color ret;
      try {
          ret = (Color)colourMappings.get((String)nameColourMappings.get(name));
      }
      catch(Exception e) {
          return null;    
      }
      return ret;
  }
}
